package thread;

import org.junit.Test;

import java.util.Random;
import java.util.concurrent.CountDownLatch;


/**
 * 模拟买票测试
 */
public class SynchronizedTest {

	/**
	 * 构造方法加synchronized并不会报错，只是没有意义，因为jvm会保证构造方法的同步
	 */
	public synchronized void SynchronizedTest() {

	}

    @Test
    public void testTicket() throws InterruptedException {
//		Runnable ticket = new BadTicket();
//		Runnable ticket = new GoodTicket();
        Runnable ticket = new VeryGoodTicket();
        Thread tA = new Thread(ticket, "A");
        Thread tB = new Thread(ticket, "B");
        Thread tC = new Thread(ticket, "C");
        Thread tD = new Thread(ticket, "D");
        Thread tE = new Thread(ticket, "E");
        Thread tF = new Thread(ticket, "F");
        tA.start();
        tB.start();
        tC.start();
        tD.start();
        tE.start();
        tF.start();
    }

	/**
	 * 这个例子证明获取class锁，并不带影响其他没有加同步的方法和属性的调用
	 * @throws InterruptedException
	 */
	@Test
	public void testSyncStatic() throws InterruptedException {

		CountDownLatch countDownLatch = new CountDownLatch(2);
		Thread t1 = new Thread() {
			@Override
			public void run() {
				try {
					staticSay1();
					countDownLatch.countDown();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};

		Thread t2 = new Thread() {
			@Override
			public void run() {
				try {
					staticSay2();
					countDownLatch.countDown();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};

		t1.start();
		Thread.sleep(1000);
		t2.start();

		countDownLatch.await();
	}

	public static synchronized void staticSay1() throws InterruptedException {
		System.out.println("say1 start....");
		Thread.sleep(10000);
		System.out.println("say1 end....");
	}

	public static void staticSay2() throws InterruptedException {
		System.out.println("say2....");
	}

	@Test
	public void testSyncObj() throws InterruptedException {
		CountDownLatch countDownLatch = new CountDownLatch(2);
		Thread t1 = new Thread() {
			@Override
			public void run() {
				try {
					say1();
					countDownLatch.countDown();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};

		Thread t2 = new Thread() {
			@Override
			public void run() {
				try {
					say2();
					countDownLatch.countDown();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};

		t1.start();
		Thread.sleep(1000);
		t2.start();

		countDownLatch.await();
	}

	public synchronized void say1() throws InterruptedException {
		System.out.println("say1 start....");
		Thread.sleep(10000);
		System.out.println("say1 end....");
	}

	public void say2() throws InterruptedException {
		System.out.println("say2....");
	}

	@Test
	public void testSyncClassObj() throws InterruptedException {
		CountDownLatch countDownLatch = new CountDownLatch(2);
		Thread t1 = new Thread() {
			@Override
			public void run() {
				try {
					staticSay1();
					countDownLatch.countDown();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};

		Thread t2 = new Thread() {
			@Override
			public void run() {
				try {
					say1();
					countDownLatch.countDown();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};

		t1.start();
		Thread.sleep(1000);
		t2.start();

		countDownLatch.await();
	}
}

/**
 * 错误的
 */
class BadTicket implements Runnable {

    public Integer ticket = 10;
    public Random random = new Random();

    @Override
    public void run() {

        while (ticket > 0) {

            try {
                Thread.sleep(random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "抢到票，剩余票数：" + (--ticket));
        }
    }
}

class GoodTicket implements Runnable {

    public Integer ticket = 10;
    public Random random = new Random();

    @Override
    public synchronized void run() {

        while (ticket > 0) {

            try {
                Thread.sleep(random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "抢到票，剩余票数：" + (--ticket));
        }
    }
}

class VeryGoodTicket implements Runnable {

    public Integer ticket = 10;
    public Random random = new Random();

    @Override
    public void run() {

        while (ticket > 0) {

            synchronized (this) {

                if (ticket <= 0) {
                    return;
                }
                try {
                    Thread.sleep(random.nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "抢到票，剩余票数：" + (--ticket));
            }
        }
    }
}
